package com.liu.controller;


import com.liu.constant.RedisConstant;
import com.liu.entity.Goods;
import com.liu.error.BusinessException;
import com.liu.response.Result;
import com.liu.service.ActivityService;
import com.liu.service.CacheService;
import com.liu.service.GoodsService;
import com.liu.vo.GoodsDetailVo;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 商品controller
 */
@RestController()
@RequestMapping("/goods")
public class GoodsController {

    @Autowired
    private GoodsService goodsService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private CacheService cacheService;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private ActivityService activityService;
    /**
     * 发布活动
     */
    @RequestMapping(value = "/publishActivity", method = {RequestMethod.GET})
    @ResponseBody
    public Result publishActivity(@RequestParam(name = "activityId") Long activityId) {
        activityService.publishActivity(activityId);
        return Result.success();
    }

    //商品列表页面浏览
    @RequestMapping(value = "/list",method = {RequestMethod.GET})
    @ResponseBody
    public Result listGoods(){
        List<Goods> goodsList = goodsService.listGoods();
        return Result.create(goodsList);
    }

    //商品详情
//    @SentinelResource(value = "createOrderLimiting" , blockHandler = "handleException")
    @RequestMapping(value = "/getGoodsDetail", method = {RequestMethod.GET})
    @ResponseBody
    public Result getGood(@RequestParam(name = "goodsId") Long goodsId) throws BusinessException, InterruptedException {
        //首先在本地本地缓存中查询是否有次商品信息
        Object cache = cacheService.getCache(goodsId + "");
        if(cache!=null) return Result.create(cache);
        GoodsDetailVo o = (GoodsDetailVo)redisTemplate.opsForValue().get(RedisConstant.goodsDetail + goodsId);
        if(o!=null){
            cacheService.setCache(goodsId+"",o);
            return Result.create(o);
        }
        //去数据库中查询
        //上锁先
        RLock lock = redissonClient.getLock(RedisConstant.goodsDetailLock + goodsId);
        boolean b = lock.tryLock(1, 1, TimeUnit.SECONDS);
        ReentrantLock reentrantLock;
        if(b){
            try{
                //首先判断redis中是否有      （这个地方是因为已经有人拿到锁了，然后
                GoodsDetailVo goods1 = (GoodsDetailVo)redisTemplate.opsForValue().get(RedisConstant.goodsDetail + goodsId);
                if(goods1!=null) return Result.create(goods1);
                //数据库中查询
                GoodsDetailVo goodsByIda = goodsService.getGoodsById(goodsId);
                //redis中和本地缓存中都存一份
                cacheService.setCache(goodsId+"",goodsByIda);
                redisTemplate.opsForValue().set(RedisConstant.goodsDetail + goodsId,goodsByIda);
                return Result.create(goodsByIda);
            }catch (Exception e){
                System.out.println("查询数据库失败！");
            }finally {
                if(lock.isLocked()){
                    lock.unlock();
                }
            }
        }
        else{
            //到这边意味没有拿到锁
            //首先判断redis中是否含有数据
            GoodsDetailVo goods1 = (GoodsDetailVo)redisTemplate.opsForValue().get(RedisConstant.goodsDetail + goodsId);
            if(goods1!=null) return Result.create(goods1);
            //如果没有数据代表一分钟的时间，开始拿到锁的线程还没有把数据查询出来，这时候我们需要自己去查询
            reentrantLock=new ReentrantLock();
            reentrantLock.lock();
            try {
                GoodsDetailVo goods2 = (GoodsDetailVo)redisTemplate.opsForValue().get(RedisConstant.goodsDetail + goodsId);//双重检验
                if(goods2!=null) return Result.create(goods1);
                GoodsDetailVo goodsByIdb = goodsService.getGoodsById(goodsId);
                cacheService.setCache(goodsId+"",goodsByIdb);
                redisTemplate.opsForValue().set(RedisConstant.goodsDetail + goodsId,goodsByIdb);
            }catch (Exception e){
                System.out.println("获取锁失败");
            }finally {
                lock.unlock();
            }
        }
        GoodsDetailVo goodsById = goodsService.getGoodsById(goodsId);
        return Result.create(goodsById);
    }

//    public Result handleException(@RequestParam(name = "goodsId") Long goodsId, BlockException ex) {
//        System.out.println("被限流了");
//        return Result.create(null);
//    }
}
